package com.pioneer.web.sale.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pioneer.common.exception.CustomException;
import com.pioneer.common.utils.SecurityUtils;
import com.pioneer.web.archive.domain.ArcInventory;
import com.pioneer.web.archive.mapper.ArcInventoryMapper;
import com.pioneer.web.sale.domain.SalContract;
import com.pioneer.web.sale.domain.SalContractBody;
import com.pioneer.web.sale.mapper.SalContractBodyMapper;
import com.pioneer.web.sale.mapper.SalContractMapper;
import com.pioneer.web.sale.service.ISalContractService;
import com.pioneer.web.sale.service.ISalOrderService;
import jakarta.annotation.Resource;
import org.apache.ibatis.executor.BatchResult;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * SalContractServiceImpl
 *
 * @author hlm
 * @date 2025-04-22 09:05:44
 */
@Service
public class SalContractServiceImpl extends ServiceImpl<SalContractMapper, SalContract> implements ISalContractService {

    @Resource
    private SalContractBodyMapper contractBodyMapper;

    @Resource
    private ArcInventoryMapper inventoryMapper;

    @Resource
    private ISalOrderService orderService;

    @Override
    public SalContract getContractById(Long contractId) {
        // 方法1：先查询销售合同，再查询销售合同子表
//        SalContract salContract = getById(contractId);
//        LambdaQueryWrapper<SalContractBody> bodyQuery = Wrappers.lambdaQuery();
//        bodyQuery.eq(SalContractBody::getContractId, contractId);
//        List<SalContractBody> contractBodyList = contractBodyMapper.selectList(bodyQuery);
//        salContract.setContractBodyList(contractBodyList);
//        return salContract;

        // 方法2：一条sql直接返回
        return getBaseMapper().getContractById(contractId);
    }

    @Override
    public boolean addContract(SalContract contract) {
        // 获取子表信息
        List<SalContractBody> contractBodyList = contract.getContractBodyList();
        if (CollUtil.isEmpty(contractBodyList)) {
            throw new CustomException("销售合同子表信息不能为空");
        }
        // 1.保存销售合同
        SalContract addContract = dealData(contract);
        boolean ret = save(addContract);
        if (!ret) {
            throw new CustomException("保存销售合同失败");
        }
        // 关联主表id
        contractBodyList = contractBodyList.stream().peek(b -> b.setContractId(addContract.getContractId())).toList();
        // 2.批量保存销售合同子表
        int bodyRet = contractBodyMapper.insertBatch(contractBodyList);
        if (bodyRet <= 0) {
            throw new CustomException("保存销售合同子表失败");
        }
        return true;
    }

    @Override
    public boolean editContract(SalContract contract) {
        SalContract salContract = getContractById(contract.getContractId());
        if (salContract == null) {
            throw new CustomException("单据不存在，请刷新后重试");
        }
        if (!"0".equals(contract.getApproveStatus())) {
            throw new CustomException("只有合同状态为初始的数据才可以修改");
        }
        List<SalContractBody> newContractBodyList = contract.getContractBodyList();
        if (CollUtil.isEmpty(newContractBodyList)) {
            throw new CustomException("销售合同子表信息不能为空");
        }
        // 1.修改销售合同
        SalContract updateContract = dealData(contract);
        updateById(updateContract);
        // 2.修改销售合同子表
        // 方法1：先删除，再插入
//        // 删除子表
//        LambdaQueryWrapper<SalContractBody> bodyDelete = Wrappers.lambdaQuery();
//        bodyDelete.eq(SalContractBody::getContractId, contract.getContractId());
//        contractBodyMapper.delete(bodyDelete);
//        // 批量插入子表
//        contractBodyMapper.insertBatch(newContractBodyList);

        // 方法2：新增、修改、删除分别处理
        // 获取修改前的子表记录
        List<SalContractBody> oldContractBodyList = salContract.getContractBodyList();
        // 需要新增的数据集合
        List<SalContractBody> insertContractBodyList = newContractBodyList.stream().filter(b -> b.getContractBodyId() == null).toList();
        // 需要修改的数据集合
        List<SalContractBody> updateContractBodyList = new ArrayList<>();
        // 需要删除的数据集合
        List<SalContractBody> deleteContractBodyList = new ArrayList<>();

        for (SalContractBody oldBody : oldContractBodyList) {
            // 匹配销售合同子表ID数据
            newContractBodyList.stream().filter(newBody -> oldBody.getContractBodyId().equals(newBody.getContractBodyId())).findFirst()
                    .ifPresent(updateContractBodyList::add);
            // 旧数据ID在新数据中是否存在
            long count = newContractBodyList.stream().filter(newBody -> oldBody.getContractBodyId().equals(newBody.getContractBodyId())).count();
            if (count <= 0) {
                // 被删除了
                deleteContractBodyList.add(oldBody);
            }
        }
        if (CollUtil.isNotEmpty(insertContractBodyList)) {
            insertContractBodyList = insertContractBodyList.stream().peek(b -> b.setContractId(updateContract.getContractId())).toList();
            // 批量新增
            contractBodyMapper.insertBatch(insertContractBodyList);
        }
        if (CollUtil.isNotEmpty(updateContractBodyList)) {
            // 批量修改
            contractBodyMapper.updateById(updateContractBodyList);
        }
        if (CollUtil.isNotEmpty(deleteContractBodyList)) {
            // 批量删除
            contractBodyMapper.deleteByIds(deleteContractBodyList);
        }
        return true;
    }

    @Override
    public boolean removeContract(List<Long> list) {
        List<SalContract> contractList = listByIds(list);
        if (CollUtil.isNotEmpty(contractList)) {
            for (SalContract contract : contractList) {
                if (!"0".equals(contract.getApproveStatus())) {
                    throw new CustomException("只有合同状态为初始的数据才可以删除");
                }
            }
            // 1.删除销售合同子表
            LambdaQueryWrapper<SalContractBody> bodyDelete = Wrappers.lambdaQuery();
            bodyDelete.in(SalContractBody::getContractId, list);
            contractBodyMapper.delete(bodyDelete);
            // 2.删除销售合同
            return removeByIds(list);
        }
        return true;
    }

    @Override
    public boolean commitContract(List<Long> contractIdList) {
        // 根据ID集合查询销售合同
        List<SalContract> contractList = getBaseMapper().selectBatchIds(contractIdList);
        List<SalContract> commitContractList = new ArrayList<>();
        for (SalContract salContract : contractList) {
            // 校验合同状态
            if (!"0".equals(salContract.getApproveStatus())) {
                throw new CustomException("合同编号[" + salContract.getContractCode() + "]数据的不是初始状态，不允许提交");
            }
            // 执行提交：合同状态 0 -> 1
            SalContract commitContract = new SalContract();
            commitContract.setContractId(salContract.getContractId());
            commitContract.setApproveStatus("1");
            commitContractList.add(commitContract);
        }
        List<BatchResult> results = getBaseMapper().updateById(commitContractList);
        if (CollUtil.isEmpty(results)) {
            throw new CustomException("提交失败");
        }
        return true;
    }

    @Override
    public boolean recallContract(List<Long> contractIdList) {
        // 根据ID集合查询销售合同
        List<SalContract> contractList = getBaseMapper().selectBatchIds(contractIdList);
        List<SalContract> recallContractList = new ArrayList<>();
        for (SalContract salContract : contractList) {
            // 校验合同状态
            if (!"1".equals(salContract.getApproveStatus())) {
                throw new CustomException("合同编号[" + salContract.getContractCode() + "]的数据不是审批中状态，不允许撤回");
            }
            // 执行撤回：合同状态 1 -> 0
            SalContract recallContract = new SalContract();
            recallContract.setContractId(salContract.getContractId());
            recallContract.setApproveStatus("0");
            recallContractList.add(recallContract);
        }
        List<BatchResult> results = getBaseMapper().updateById(recallContractList);
        if (CollUtil.isEmpty(results)) {
            throw new CustomException("撤回失败");
        }
        return true;
    }

    @Override
    public boolean approveContract(SalContract contract) {
        SalContract salContract = getContractById(contract.getContractId());
        if (salContract == null) {
            throw new CustomException("单据不存在，请刷新后重试");
        }
        if (!"1".equals(salContract.getApproveStatus())) {
            throw new CustomException("只有合同状态为审批中的数据才可以审批");
        }
        // 构建需要审批的销售合同
        SalContract approveContract = new SalContract();
        approveContract.setContractId(contract.getContractId());
        approveContract.setApprover(SecurityUtils.getLoginUser().getUsername());
        approveContract.setApproveTime(LocalDateTime.now());
        approveContract.setApproveOpinion(contract.getApproveOpinion());
        String approveResult = contract.getApproveResult();
        if (StrUtil.isBlank(approveResult)) {
            throw new CustomException("审批结果不能为空，请选择");
        }
        switch (approveResult) {
            case "pass" -> {
                // 审批通过：将合同状态改为审批通过
                approveContract.setApproveStatus("2");
                // 并自动生成一张销售订单
                boolean orderRet = orderService.genOrderByContract(salContract);
                if (!orderRet) {
                    throw new CustomException("生成销售订单失败");
                }
            }
            case "nopass" -> {
                // 审批不通过：审批意见必填
                String approveOpinion = approveContract.getApproveOpinion();
                if (StrUtil.isBlank(approveOpinion)) {
                    throw new CustomException("审批意见不能为空");
                }
                // 将合同状态改为审批不通过
                approveContract.setApproveStatus("3");
            }
            case "reject" -> {
                // 驳回：审批意见必填
                String approveOpinion = approveContract.getApproveOpinion();
                if (StrUtil.isBlank(approveOpinion)) {
                    throw new CustomException("审批意见不能为空");
                }
                // 确认后将合同状态改为初始
                approveContract.setApproveStatus("0");
            }
        }
        // 执行审批
        return getBaseMapper().approveContract(approveContract);
    }

    @Override
    public boolean unapproveContract(SalContract contract) {
        SalContract salContract = getById(contract.getContractId());
        if (salContract == null) {
            throw new CustomException("单据不存在，请刷新后重试");
        }
        if (!"2".equals(salContract.getApproveStatus()) && !"3".equals(salContract.getApproveStatus())) {
            throw new CustomException("只有合同状态为审批中的数据才可以审批");
        }
        // 删除自动生成的销售订单
        boolean orderRet = orderService.delOrderByContract(salContract);
        if (!orderRet) {
            throw new CustomException("删除销售订单失败");
        }
        // 构建需要审批的销售合同
        SalContract unapproveContract = new SalContract();
        unapproveContract.setContractId(contract.getContractId());
        unapproveContract.setApproveStatus("1");
        unapproveContract.setApprover(null);
        unapproveContract.setApproveTime(null);
        unapproveContract.setApproveOpinion(null);
        // 执行审批
        return getBaseMapper().approveContract(unapproveContract);
    }

    /**
     * 数据处理
     * @param contract 销售合同
     * @return 结果
     */
    private SalContract dealData(SalContract contract) {
        // 获取前端提交的销售合同子表信息集合
        List<SalContractBody> contractBodyList = contract.getContractBodyList();
        // 获取其中的存货ID集合（去重）： 2，2，100 -> 2, 100
        Set<Long> contractBodyInventoryIdList = contractBodyList.stream().map(SalContractBody::getInventoryId).collect(Collectors.toSet());
        // 根据存货ID集合查询数据库：select inventory_id from arc_inventory where inventory_id in (2, 100) -> 2
        LambdaQueryWrapper<ArcInventory> query = Wrappers.lambdaQuery();
        query.select(ArcInventory::getInventoryId).in(ArcInventory::getInventoryId, contractBodyInventoryIdList);
        List<Long> inventoryIdList = inventoryMapper.selectObjs(query);

        // 合同金额
        BigDecimal total = BigDecimal.ZERO;
        for (int i = 0; i < contractBodyList.size(); i++) {
            SalContractBody salContractBody = contractBodyList.get(i);
            // 校验存货管理
            Long inventoryId = salContractBody.getInventoryId();
            if (!inventoryIdList.contains(inventoryId)) {
                throw new CustomException("第" + (i + 1) + "行的存货管理不是有效值，请重新输入");
            }
            // 校验销售数量
            BigDecimal saleNumber = salContractBody.getSaleNumber();
            if (saleNumber == null || saleNumber.doubleValue() <= 0) {
                throw new CustomException("第" + (i + 1) + "行的销售数量必须大于0");
            }
            // 校验销售单价
            BigDecimal salePrice = salContractBody.getSalePrice();
            if (salePrice == null || salePrice.doubleValue() < 0) {
                throw new CustomException("第" + (i + 1) + "行的销售单价必须大于等于0");
            }
            // 计算每一行销售总价=销售数量*销售单价
            salContractBody.setSaleTotal(saleNumber.multiply(salePrice));
            // 计算合同金额（逐行累加）
            total = total.add(salContractBody.getSaleTotal());
        }
        // 1.保存销售合同
        SalContract dealContract = new SalContract();
        dealContract.setContractName(contract.getContractName());
        dealContract.setCustomer(contract.getCustomer());
        dealContract.setTotal(total);
        if (contract.getContractId() == null) {
            // 新增
            dealContract.setContractCode(genContractCode());
            dealContract.setApproveStatus("0");
        } else {
            // 修改（关联销售合同ID）
            dealContract.setContractId(contract.getContractId());
        }
        return dealContract;
    }

    /**
     * 生成销售合同编号
     * @return 结果
     */
    private String genContractCode() {
        // 根据指定格式获取当天字符串
        String today = DateUtil.format(new Date(), "yyyyMMdd");
        // 查询当天最大流水号记录
        String maxCode = getBaseMapper().selectMaxCode(today);
        if (StrUtil.isBlank(maxCode)) {
            // 当天没有流水号，直接返回
            return "CONTRACT" + today + "001";
        } else {
            // 截取最后三位
            String oldCode = maxCode.substring(maxCode.length() - 3);
            // 流水号+1并补0
            String newCode = String.format("%03d", Integer.parseInt(oldCode) + 1);
            // 返回新的流水号
            return "CONTRACT" + today + newCode;
        }
    }
}
